package com.houweishi.module.clocking.service.impl;

import com.houweishi.common.constant.Constants;
import com.houweishi.common.core.domain.AjaxResult;
import com.houweishi.common.core.domain.entity.SysDept;
import com.houweishi.common.core.domain.model.LoginUser;
import com.houweishi.common.exception.base.BaseException;
import com.houweishi.common.utils.DateUtils;
import com.houweishi.common.utils.SecurityUtils;
import com.houweishi.module.clockbinding.mapper.BizClockingBindingMapper;
import com.houweishi.module.clocking.domain.BizClocking;
import com.houweishi.module.clocking.mapper.BizClockingMapper;
import com.houweishi.module.clocking.service.IBizClockingService;
import com.houweishi.module.clockingcount.domain.BizClockingCount;
import com.houweishi.module.clockingcount.mapper.BizClockingCountMapper;
import com.houweishi.module.clockscope.mapper.BizClockingScopeMapper;
import com.houweishi.module.leave.mapper.OaLeaveMapper;
import com.houweishi.module.staff.domain.BizStaff;
import com.houweishi.module.staff.service.IBizStaffService;
import com.houweishi.system.service.ISysDeptService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static com.houweishi.common.utils.PageUtils.startPage;

/**
 * 员工打卡管理Service业务层处理
 *
 * @author houweishi
 * @date 2023-02-28
 */
@Service
public class BizClockingServiceImpl implements IBizClockingService {
    private static final Logger log = LoggerFactory.getLogger(BizClockingServiceImpl.class);

    int a = 0;
    @Resource
    private BizClockingMapper bizClockingMapper;

    @Resource
    private BizClockingCountMapper bizClockingCountMapper;

    @Resource
    private BizClockingScopeMapper bizClockingScopeMapper;

    @Resource
    private ISysDeptService iSysDeptService;

    /**
     * 员工Service
     */
    @Resource
    private IBizStaffService iBizStaffService;

    /**
     * 请假申请Mapper
     */
    @Resource
    private OaLeaveMapper oaLeaveMapper;

    /**
     * 员工与打卡类型绑定Mapper接口
     */
    @Resource
    private BizClockingBindingMapper bizClockingBindingMapper;

    /**
     * 查询员工打卡管理
     *
     * @param id 员工打卡管理主键
     * @return 员工打卡管理
     */
    @Override
    public BizClocking selectBizClockingById(Long id) {
        return bizClockingMapper.selectBizClockingById(id);
    }

    /**
     * 查询员工打卡管理列表
     *
     * @param bizClocking 员工打卡管理
     * @return 员工打卡管理
     */
    @Override
    public List<BizClocking> selectBizClockingList(BizClocking bizClocking) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (Objects.isNull(loginUser)) {
            throw new BaseException("请先登录");
        }
        // 获取登录人部门
        SysDept dept = iSysDeptService.selectDeptById(loginUser.getDeptId());
        if (Objects.isNull(dept)) {
            throw new BaseException("部门信息为空");
        }
        // 获取当前人公司
        List<String> companyList = Arrays.asList(Constants.DX, Constants.YS, Constants.WY);
        if (companyList.contains(dept.getDeptName())) {
            bizClocking.setCompany(dept.getDeptName());
        } else if (Constants.HWS.equals(dept.getDeptName()) || Constants.SR.equals(dept.getDeptName())) {

        } else {
            bizClocking.setUserId(loginUser.getUserId());
        }
        startPage();
        List<BizClocking> bizClockings = bizClockingMapper.selectBizClockingList(bizClocking);
        return bizClockings;
    }

    /**
     * 新增员工打卡管理
     *
     * @param bizClocking 员工打卡管理
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult insertBizClocking(BizClocking bizClocking) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (Objects.isNull(loginUser)) {
            return AjaxResult.success("请先登录");
        }
        setDeptInfoAndCompany(bizClocking, loginUser);
        bizClocking.setCreateBy(loginUser.getUsername());
        bizClocking.setCreateTime(DateUtils.getNowDate());
        bizClockingMapper.insertBizClocking(bizClocking);
        return AjaxResult.success();
    }


    /**
     * 校验同时间段是否重复打卡(废弃)
     *
     * @param bizClocking 员工打卡管理
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    public int checkClockingTime(BizClocking bizClocking) {
        // LoginUser loginUser = SecurityUtils.getLoginUser();
        // if (Objects.isNull(loginUser)){
        //     throw new BaseException("请先登录");
        // }
        // List<BizClocking> list2 = new ArrayList<>();
        // //拿到打卡时间，打卡类型id，判断是否已经有打卡时间范围内的记录了
        // try {
        //     if (bizClocking.getClockTypeId() != null || bizClocking.getClockTime() != null) {
        //         //查询此打卡类型下的所有时间段
        //         BizClockingScope bizClockingScope = new BizClockingScope();
        //         bizClockingScope.setTypeId(bizClocking.getClockTypeId());
        //         List<BizClockingScope> scopeList = bizClockingScopeMapper.selectBizClockingScopeList(bizClockingScope);
        //         if (!CollectionUtils.isEmpty(scopeList)) {
        //             scopeList.forEach(scope -> {
        //                 SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss"); // 设置日期格式
        //                 LocalDate now = bizClocking.getClockTime();
        //                 String nowTime = df.format(now);
        //                 String beginTime = scope.getStartTime();
        //                 String endTime = scope.getEndTime();
        //                 try {
        //                     // 获取开始时间和结束时间的Calendar对象
        //                     Calendar startCalendar = Calendar.getInstance();
        //                     startCalendar.setTime(df.parse(beginTime));
        //                     Calendar endCalendar = Calendar.getInstance();
        //                     endCalendar.setTime(df.parse(endTime));
        //                     // 获取当前时间的Calendar对象
        //                     Calendar nowCalendar = Calendar.getInstance();
        //                     nowCalendar.setTime(df.parse(nowTime));
        //                     // 判断当前时间是否在两个时间点内
        //                     if (nowCalendar.after(startCalendar) && nowCalendar.before(endCalendar)) {
        //                         System.out.println("当前时间在" + beginTime + "和" + endTime + "之间");
        //                         //如果在时间范围内。则查询今天此人之前的打卡记录集合
        //                         BizClocking bizClocking1 = new BizClocking();
        //                         bizClocking1.setUserId(bizClocking.getUserId());
        //                         bizClocking1.setClockTime(bizClocking.getClockTime());
        //                         List<BizClocking> list = bizClockingMapper.selectUserBizClockingListToday2(bizClocking1);
        //
        //                         //如果之前有打卡记录，则校验是否有同一个时间区间的打卡记录，重复打卡
        //                         if (!CollectionUtils.isEmpty(list)) {
        //                             list.forEach(clocking -> {
        //                                 LocalDate now2 = bizClocking.getClockTime();
        //                                 String nowTime2 = df.format(now2);
        //                                 try {
        //                                     Calendar nowCalendar1 = Calendar.getInstance();
        //                                     nowCalendar1.setTime(df.parse(nowTime2));//这条打卡记录的时间
        //
        //                                     if (nowCalendar1.after(startCalendar) && nowCalendar1.before(endCalendar)) {
        //                                         list2.add(clocking);
        //                                     }
        //                                 } catch (ParseException e) {
        //                                     log.error("时间转换异常",e);
        //                                     throw new BaseException("时间转换异常");
        //                                 }
        //                             });
        //                             //没有打卡时间重复的，则新增
        //                             if (list2.size() > 0) {
        //                                 a=1;
        //                             }
        //                             setDeptInfoAndCompany(bizClocking,loginUser);
        //                             bizClockingMapper.insertBizClocking(bizClocking);
        //                         } else {
        //                             //如果之前没有打卡记录则直接新增
        //                             setDeptInfoAndCompany(bizClocking,loginUser);
        //                             bizClockingMapper.insertBizClocking(bizClocking);
        //                         }
        //                     }
        //                 } catch (Exception e) {
        //                     log.error("时间转换异常2",e);
        //                     throw new BaseException("时间转换异常2");
        //                 }
        //             });
        //         }
        //     }
        // } catch (Exception e) {
        //     log.error("打卡失败",e);
        //     throw new RuntimeException("打卡失败", e);
        // }
        // return a;
        return 0;
    }

    /**
     * 设置公司及部门信息
     *
     * @param bizClocking
     * @param loginUser
     */
    private void setDeptInfoAndCompany(BizClocking bizClocking, LoginUser loginUser) {
        SysDept dept = iSysDeptService.selectDeptById(loginUser.getDeptId());
        if (Objects.isNull(dept)) {
            throw new BaseException("部门不存在");
        }
        bizClocking.setCompany(dept.getParentName());
        bizClocking.setDeptName(dept.getDeptName());
        bizClocking.setDeptId(dept.getDeptId());
    }

    /**
     * 校验同时间段是否重复打卡
     *
     * @param bizClocking 员工打卡管理
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    void checkClockingTime2(BizClocking bizClocking) {
        // //拿到打卡时间，打卡类型id，判断是否已经有打卡时间范围内的记录了
        // //        try {
        // if (bizClocking.getClockTypeId() != null || bizClocking.getClockTime() != null) {
        //     //查询此打卡类型下的所有时间段
        //     BizClockingScope bizClockingScope = new BizClockingScope();
        //     bizClockingScope.setTypeId(bizClocking.getClockTypeId());
        //     List<BizClockingScope> scopeList = bizClockingScopeMapper.selectBizClockingScopeList(bizClockingScope);
        //     if (!CollectionUtils.isEmpty(scopeList)) {
        //         scopeList.forEach(scope -> {
        //             SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss"); // 设置日期格式
        //             // Date now = bizClocking.getClockTime();
        //             String nowTime = df.format(now);
        //             String beginTime = scope.getStartTime();
        //             String endTime = scope.getEndTime();
        //             System.out.println("===============" + nowTime);
        //             try {
        //                 if (df.parse(nowTime).getTime() > df.parse(beginTime).getTime() && df.parse(nowTime).getTime() < df.parse(endTime).getTime()) {
        //                     System.out.println("===============");
        //                 }
        //             } catch (ParseException e) {
        //                 e.printStackTrace();
        //             }
        //
        //             try {
        //                 // 获取开始时间和结束时间的Calendar对象
        //                 Calendar startCalendar = Calendar.getInstance();
        //                 startCalendar.setTime(df.parse(beginTime));
        //                 Calendar endCalendar = Calendar.getInstance();
        //                 endCalendar.setTime(df.parse(endTime));
        //                 // 获取当前时间的Calendar对象
        //                 Calendar nowCalendar = Calendar.getInstance();
        //                 nowCalendar.setTime(df.parse(nowTime));
        //                 // 判断当前时间是否在两个时间点内
        //                 if (nowCalendar.after(startCalendar) && nowCalendar.before(endCalendar)) {
        //                     System.out.println("当前时间在" + beginTime + "和" + endTime + "之间");
        //                     //如果在时间范围内。则查询今天此人之前的打卡记录集合
        //                     List<BizClocking> list = bizClockingMapper.selectUserBizClockingListToday2(bizClocking);
        //                     List<BizClocking> list2 = new ArrayList<>();
        //                     //如果之前有打卡记录，则校验是否有同一个时间区间的打卡记录，重复打卡
        //                     if (!CollectionUtils.isEmpty(list)) {
        //                         list.forEach(clocking -> {
        //                             Date now2 = bizClocking.getClockTime();
        //                             String nowTime2 = df.format(now2);
        //                             try {
        //                                 Calendar nowCalendar1 = Calendar.getInstance();
        //                                 nowCalendar1.setTime(df.parse(nowTime2));//这条打卡记录的时间
        //
        //                                 if (nowCalendar1.after(startCalendar) && nowCalendar1.before(endCalendar)) {
        //                                     list2.add(clocking);
        //                                     throw new RuntimeException("请勿重复打卡");
        //                                 }
        //                             } catch (ParseException e) {
        //                                 e.printStackTrace();
        //                             }
        //                         });
        //                         //没有打卡时间重复的，则新增
        //                         if (list2.size() == 0) {
        //                             bizClockingMapper.insertBizClocking(bizClocking);
        //                         }
        //                     } else {//如果之前没有打卡记录则直接新增
        //                         bizClockingMapper.insertBizClocking(bizClocking);
        //                     }
        //                 }
        //             } catch (Exception e) {
        //                 e.printStackTrace();
        //             }
        //         });
        //     }
        // }
        //        } catch (Exception e) {
        //            throw new RuntimeException("打卡失败", e);
        //        }
    }


    /**
     * 修改员工打卡管理
     *
     * @param bizClocking 员工打卡管理
     * @return 结果
     */
    @Override
    public int updateBizClocking(BizClocking bizClocking) {
        bizClocking.setUpdateTime(DateUtils.getNowDate());
        return bizClockingMapper.updateBizClocking(bizClocking);
    }

    /**
     * 批量删除员工打卡管理
     *
     * @param ids 需要删除的员工打卡管理主键
     * @return 结果
     */
    @Override
    public int deleteBizClockingByIds(Long[] ids) {
        return bizClockingMapper.deleteBizClockingByIds(ids);
    }

    /**
     * 删除员工打卡管理信息
     *
     * @param id 员工打卡管理主键
     * @return 结果
     */
    @Override
    public int deleteBizClockingById(Long id) {
        return bizClockingMapper.deleteBizClockingById(id);
    }

    /**
     * 查询某员工打卡当天打卡记录列表
     *
     * @param bizClocking 员工打卡管理
     * @return 员工打卡管理集合
     */
    @Override
    public List<BizClocking> selectUserBizClockingListToday(BizClocking bizClocking) {
        return bizClockingMapper.selectUserBizClockingListToday2(bizClocking);
    }

    /**
     * 定时查询并记录前一天打卡记录情况
     *
     * @return 员工打卡管理集合
     */
    @Transactional
    @Override
    public List<BizClockingCount> selectBizClockingListToday(BizClocking bizClocking) {
        List<BizClockingCount> bizClockingCountList = new ArrayList<>();
        //
        // //一天内所有考勤记录（昨天）
        // List<BizClocking> clockingList = bizClockingMapper.selectBizClockingListToday(bizClocking);
        //
        // // list根据StaffId去重
        // //        List<BizClocking> list = clockingList.stream().filter(distinctByKey(e -> e.getStaffId())).collect(Collectors.toList());
        // List<BizClocking> list = clockingList.stream().collect(
        //         Collectors.collectingAndThen(Collectors.toCollection(
        //                 () -> new TreeSet<>(Comparator.comparing(BizClocking::getStaffId))), ArrayList::new));
        //
        // if (!CollectionUtils.isEmpty(list)) {
        //     list.forEach(clock -> {
        //
        //         BizClockingCount bizClockingCount = new BizClockingCount();
        //         bizClockingCount.setStaffId(clock.getStaffId());
        //         bizClockingCount.setStaffName(clock.getStaffName());
        //         bizClockingCount.setClockDate(clock.getClockTime());
        //         bizClockingCount.setCreateTime(DateUtils.getNowDate());
        //
        //         //此人今天打卡合格记录条数
        //         BizClocking bizClocking1 = new BizClocking();
        //         //                bizClocking1.setUserId(clock.getUserId());
        //         //                bizClocking1.setClockTime(clock.getClockTime());
        //         bizClocking1.setStaffId(clock.getStaffId());
        //         bizClocking1.setClockStatus("0");
        //         List<BizClocking> clockingList1 = bizClockingMapper.selectBizClockingListToday2(bizClocking1);//查当天
        //         if (!CollectionUtils.isEmpty(clockingList1)) {
        //             int sum1 = clockingList1.size();
        //             //此人今天应打卡次数
        //             BizClockingScope bizClockingScope = new BizClockingScope();
        //             bizClockingScope.setTypeId(clock.getClockTypeId());
        //             int sum2 = bizClockingScopeMapper.selectBizClockingScopeList(bizClockingScope).size();
        //             //判断打卡状态是否正常
        //             if (sum1 == sum2) {
        //                 bizClockingCount.setDayClockStatus("0");
        //             } else {
        //                 bizClockingCount.setDayClockStatus("1");
        //             }
        //             //本月已打卡天数
        //             BizClockingCount bizClockingCount1 = new BizClockingCount();
        //             bizClockingCount1.setStaffId(clock.getStaffId());
        //             bizClockingCount1.setClockDate(clock.getClockTime());
        //             List<BizClockingCount> countList = bizClockingCountMapper.selectBizClockingCountListByMonth(bizClockingCount1);
        //             int sum3 = countList.size() + 1;
        //             bizClockingCount.setClockDays(Long.valueOf(sum3));
        //
        //
        //             bizClockingCountMapper.insertBizClockingCount(bizClockingCount);
        //             bizClockingCountList.add(bizClockingCount);
        //         }
        //
        //     });
        // }
        //
        return bizClockingCountList;
    }

    /**
     * 〈功能描述〉属性去重
     *
     * @param keyExtractor
     * @return java.util.function.Predicate<T>
     * @throws
     * @author caic
     * @see
     */
    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    /**
     * 根据前一天打卡记录，判断员工打卡是否异常
     *
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult dealAttendance() {
        // 获取前一天时间
        LocalDate now = LocalDate.now();
        LocalDate lastDate = now.minusDays(1L);

        LocalTime localTime = LocalTime.now();
        LocalDateTime localDateTime = lastDate.atTime(localTime);

        // 获取前一天打卡记录
        BizClocking bizClocking = new BizClocking();
        bizClocking.setClockTime(localDateTime);
        List<BizClocking> lastClockingList = bizClockingMapper.selectBizClockingList(bizClocking);
        // 获取需要打卡员工及时长
        BizStaff bizStaff = new BizStaff();
        bizStaff.setIsClock("1");
        List<BizStaff> bizStaffs = iBizStaffService.selectBizStaffList(bizStaff);
        log.info("员工集合是否为空："+CollectionUtils.isEmpty(bizStaffs));
        if (!CollectionUtils.isEmpty(bizStaffs)) {
            List<BizClockingCount> bizClockingCounts = checkRules(lastDate, lastClockingList, bizStaffs);
            if (!CollectionUtils.isEmpty(bizClockingCounts)){
                bizClockingCountMapper.insertBatchBizClockingCount(bizClockingCounts);
            }
        }
        return AjaxResult.success();
    }

    /**
     * 校验考勤规则
     *
     * @param lastDate
     * @param lastClockingList
     * @param bizStaffs
     */
    public List<BizClockingCount> checkRules(LocalDate lastDate, List<BizClocking> lastClockingList, List<BizStaff> bizStaffs) {
        List<BizClockingCount> list = new ArrayList<>();
        List<BizClocking> collect;
        for (BizStaff staff : bizStaffs) {
            BizClockingCount bizClockingCount = new BizClockingCount();
            bizClockingCount.setDayClockStatus("0");
            // 判断员工是否打卡异常
            // 获取员工打卡记录
            collect = lastClockingList.stream()
                    .filter(a -> staff.getUserId().equals(a.getUserId()))
                    .sorted(Comparator.comparing(BizClocking::getClockTime))
                    .collect(Collectors.toList());
            if (CollectionUtils.isEmpty(collect)) {
                //    无打卡记录，查询是否请假
                Integer num = oaLeaveMapper.selectListByTimeAndBusinessStatus(lastDate, Constants.COMPLETED);
                if (Objects.isNull(num) || num <= 0) {
                    bizClockingCount.setDayClockStatus("1");
                }
                bizClockingCount.setDayClockStatus("2");
            } else {
                //    有打卡记录，根据员工打卡类型判断是否打卡是否异常
                // 员工昨天打卡时间（时分秒）
                List<LocalTime> collect1 = collect.stream().map(a -> a.getClockTime().toLocalTime()).collect(Collectors.toList());
                List<LocalTime> collect2 = new ArrayList<>();
                List<Map<String, String>> maps = bizClockingBindingMapper.selectClockingBindingByStaffId(staff.getId());
                if (!CollectionUtils.isEmpty(maps)) {
                    //    判断是否在规定区域内打卡
                    for (Map<String, String> map : maps) {
                        int i=0;
                        DateTimeFormatter localTimeFormat = DateTimeFormatter.ofPattern("HH:mm:ss");
                        // 开始时间
                        LocalTime startTime = LocalTime.parse(map.get("startTime"), localTimeFormat);
                        // 结束时间
                        LocalTime endTime = LocalTime.parse(map.get("endTime"), localTimeFormat).plusSeconds(1L);
                        // 员工打卡时间是否在开始时间和结束时间之内
                        collect2 = collect1.stream().filter(a -> {
                            return a.isBefore(endTime) && a.isAfter(startTime);
                        }).collect(Collectors.toList());
                        if (collect2.size() == 0) {
                            // 打卡异常
                            bizClockingCount.setDayClockStatus("1");
                            break;
                        }
                    }
                }
                if ("0".equals(bizClockingCount.getDayClockStatus())) {
                    //    最早时间
                    LocalDateTime earlyTime = collect.get(0).getClockTime();
                    //    最晚时间
                    LocalDateTime lastTime = collect.get(collect.size() - 1).getClockTime();
                    //    计算时长是否符合限制
                    Duration duration = Duration.between(earlyTime,lastTime);
                    long hours = duration.toHours();
                    if (hours < staff.getClockTime()) {
                        bizClockingCount.setDayClockStatus("1");
                    }
                }
            }
            bizClockingCount.setStaffId(staff.getId());
            bizClockingCount.setStaffName(staff.getUserName());
            bizClockingCount.setClockDate(lastDate);
            list.add(bizClockingCount);
        }
        return list;
    }


}
